package com.gw.vip.server.service.dao_service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gw.vip.common.constants.VipConstants;
import com.gw.vip.common.enums.StatusEnums;
import com.gw.vip.common.exception.ExceptionEnums;
import com.gw.vip.common.exception.ServiceException;
import com.gw.vip.common.util.Snowflake;
import com.gw.vip.server.dao.AccountMapper;
import com.gw.vip.server.enums.AccTypeEnums;
import com.gw.vip.server.po.Account;
import com.gw.vip.server.po.BatchClearLedger;
import com.gw.vip.server.po.SysTxnType;
import com.gw.vip.server.po.Trans;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @author GW
 * @description
 * @since 2022-05-03
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class AccountService extends ServiceImpl<AccountMapper, Account> {

    private final SysTxnTypeService sysTxnTypeService;
    private final Snowflake snowflake;
    private final SysArgService sysArgService;
    private final TransService transService;

    /**
     * 根据用户id获取帐户信息
     * @return
     */
    public List<Account> listByUserId(String userId) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserId, userId);
        return list(queryWrapper);
    }

    /**
     * 根据用户id和资金类型获取主账号
     * @param userId
     * @param capitalId
     * @return
     */
    public Account getMainAcc(String userId, String capitalId) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Account::getUserId, userId);
        queryWrapper.lambda().eq(Account::getCapitalId, capitalId);
        queryWrapper.lambda().eq(Account::getAccType, AccTypeEnums.MAIN.getKey());
        return getOne(queryWrapper);
    }

    /**
     * 获取可用余额
     * @param userId
     * @return
     */
    public BigDecimal getAvaBal(String userId) {
        return this.baseMapper.getAvaBal(userId);
    }

    /**
     * 帐户变动
     */
    public Trans change(String transId, String srcTransAccId, String txnType, BigDecimal txnAmt, String userId, String account, String capitalId, LocalDateTime txnDateTime) {
        BigDecimal updAmt = txnAmt;
        SysTxnType sysTxnType = sysTxnTypeService.getById(txnType);
        if (sysTxnType==null){
            log.error("交易类型【{}】不存在！", txnType);
            throw new ServiceException(ExceptionEnums.ERROR_SETTING, "无效交易类型");
        }
        if (sysTxnType.getBalanceDir()<0){
            updAmt = BigDecimal.ZERO.subtract(txnAmt);
        }
        int i = this.baseMapper.updateAmt(account, updAmt);
        if (i!=1){
            log.error("帐户【{}】更新金额失败， 金额【{}】", account, updAmt);
            throw new ServiceException("帐户更新金额失败");
        }

        if (sysArgService.needClear(txnDateTime)){
            //需要清算
            i = this.baseMapper.updateClearAmt(account);
            if (i!=1){
                log.error("帐户【{}】更新清算金额失败", account);
                throw new ServiceException("帐户更新清算金额失败！");
            }
        }

        Account accountAfter = this.getById(account);

        //帐户记录
        Trans trans = new Trans();
        trans.setId(snowflake.nextStringId());
        trans.setOrderId(transId);
        trans.setUserId(userId);
        trans.setAccount(account);
        trans.setCapitalId(capitalId);
        trans.setOrderType(txnType);
        trans.setTxnAmt(txnAmt);
        trans.setBalAmt(accountAfter.getAmt());
        trans.setSrcId(srcTransAccId);
        trans.setRefundAmt(BigDecimal.ZERO);
        trans.setStatus(StatusEnums.SUCCESS.getCode());
        trans.setCrtTime(txnDateTime);
        trans.setCrtName(VipConstants.SYS);
        trans.setUpdTime(txnDateTime);
        trans.setUpdName(VipConstants.SYS);
        if (!transService.save(trans)){
            log.error("保存订单失败！transId【{}】, userId【{}】", transId, userId);
            throw new ServiceException("保存订单失败！");
        }

        return trans;
    }

    public List<Account> listByChange() {
        return this.baseMapper.listByChange();
    }

    public List<BatchClearLedger> getLedger() {
        return this.baseMapper.getLedger();
    }

    public List<Account> listByLast() {
        return this.baseMapper.listByLast();
    }

    public int updateLastAmt(String id) {
        return this.baseMapper.updateLastAmt(id);
    }

    public List<Account> listByClearReady() {
        return this.baseMapper.listByClearReady();
    }

    public int updateClearAmt(String accountId) {
        return this.baseMapper.updateClearAmt(accountId);
    }

    /**
     * 更新帐户金额
     * @param account
     * @param updAmt
     * @param txnDateTime 交易时间。
     */
    public void updateAmt(String account, BigDecimal updAmt, LocalDateTime txnDateTime) {
        //todo 检查mac

        int i = this.baseMapper.updateAmt(account, updAmt);
        if (i!=1){
            log.error("帐户【{}】更新金额失败， 金额【{}】", account, updAmt);
            throw new ServiceException("帐户更新金额失败");
        }

        //在清算日内，更新清算金额
        if (sysArgService.needClear(txnDateTime)){
            //需要清算
            i = this.baseMapper.updateClearAmt(account);
            if (i!=1){
                log.error("帐户【{}】更新清算金额失败", account);
                throw new ServiceException("帐户更新清算金额失败！");
            }
        }

        //todo 设置mac
    }

    public void updateLockAmt(String account, BigDecimal updAmt, LocalDateTime txnDateTime) {
        if (StringUtils.isBlank(account)){
            log.error("account 不可为空！");
            throw new ServiceException("account 不可为空！");
        }

        if (updAmt==null){
            log.error("updAmt 不可为空！");
            throw new ServiceException("updAmt 不可为空！");
        }

        if (txnDateTime==null){
            log.error("txnDateTime 不可为空！");
            throw new ServiceException("txnDateTime 不可为空！");
        }

        int i = this.baseMapper.updateLockAmt(account, updAmt);
        if (i!=1){
            log.error("帐户【{}】更新锁定金额失败， 金额【{}】", account, updAmt);
            throw new ServiceException("帐户更新锁定金额失败");
        }
    }

    /**
     * 查找可以扣款的主账户
     * @param userId
     * @return
     */
    public List<Account> mainAvaAcc(String userId) {
        return this.baseMapper.mainAvaAcc(userId);
    }

    public List<Account> avaAccByPan(String pan) {
        return this.baseMapper.avaAccByPan(pan);
    }

    public BigDecimal getAvaBalByPan(String pan) {
        return this.baseMapper.getAvaBalByPan(pan);
    }
}
